{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# NumPy / SciPy Quiz\n",
    "\n",
    "Please do explore beyond the problems given, and feel free to ask questions at any time.\n",
    "\n",
    "If you need a quick refresher on NumPy, have a look at\n",
    "[this introduction](http://mentat.za.net/numpy/intro/intro.html).  Also see the [SciPy lectures](http://scipy-lectures.org/).\n",
    "\n",
    "If you run out of exercises, there are [100 more here!](http://www.loria.fr/~rougier/teaching/numpy.100/)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "import scipy"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The NumPy array"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Create a `3x4` array containing the numbers from 0 through 11 (using `np.arange` and `np.reshape`), and call it `x`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Predict whether `x` changes after executing the following:\n",
    "\n",
    "```python\n",
    "y = x[2]\n",
    "y[0] = 3\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Compute the sums of the columns of x, using `np.sum`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Construct the array x = np.array([0, 1, 2, 3], dtype=np.uint8).  Predict the value of `x - 1`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Broadcasting"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Consider two arrays, `x = np.arange(5); y = np.array([0.5, 1.5])`.\n",
    "\n",
    "  Construct a `5x2` matrix such that\n",
    "  `A[i, j] = x[i] * y[j]`, without using for-loops."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Given a list of XYZ-coordinates, ``p``,\n",
    "\n",
    "  ```\n",
    "  [[1.0, 2.0, 10],\n",
    "   [3.0, 4.0, 20],\n",
    "   [5.0, 6.0, 30],\n",
    "   [7.0, 8.0, 40]]\n",
    "  ```\n",
    "\n",
    "  Normalise each coordinate by dividing with its Z (3rd) element. For example,\n",
    "  the first row becomes:\n",
    "\n",
    "  ```\n",
    "  [1/10, 2/10, 10/10]\n",
    "  ```\n",
    "\n",
    "  **Hint:** extract the last column into a variable ``z``, and then change its dimensions so\n",
    "  that ``p / z`` works."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Indexing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Create a ``3x3`` ndarray, `A = np.array([[0, 1, 2], [1, 1, 3], [2, 3, 2]])`.  Find an indexing expression for extracting the diagonal elements, i.e.\n",
    "\n",
    "  `delems = A[...]`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Generate a 10 x 3 array of random numbers (all between 0 and 1). From each row, pick\n",
    "the number closest to 0.75. Make use of ``np.abs`` and ``np.argmax`` to find the\n",
    "column ``j`` which contains the closest element in each row."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Predict and verify the shape of the following slicing operation.\n",
    "\n",
    "```python\n",
    "x = np.empty((10, 8, 6))\n",
    "\n",
    "idx0 = np.zeros((3, 8)).astype(int)\n",
    "idx1 = np.zeros((3, 1)).astype(int)\n",
    "idx2 = np.zeros((1, 1)).astype(int)\n",
    "\n",
    "x[idx0, idx1, idx2]\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Optimization"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Consider the Rosenbrock test function.  You can visualize it by executing the following cell:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# From https://commons.wikimedia.org/wiki/File:Rosenbrock_function.svg\n",
    "\n",
    "from mpl_toolkits.mplot3d import Axes3D\n",
    "from matplotlib import cm\n",
    "from matplotlib.colors import LogNorm\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "def rosenbrock(x, y):\n",
    "    return (1 - x)**2 + 100 * (y - x**2)**2\n",
    "\n",
    "fig = plt.figure()\n",
    "ax = Axes3D(fig, azim = -128, elev = 43)\n",
    "s = .05\n",
    "X = np.arange(-2, 2.+s, s)\n",
    "Y = np.arange(-1, 3.+s, s)\n",
    "X, Y = np.meshgrid(X, Y)\n",
    "Z = rosenbrock(X, Y)\n",
    "# ax.plot_surface(X, Y, Z, rstride = 1, cstride = 1, norm = LogNorm(), cmap = cm.jet)\n",
    "# Without using `` linewidth=0, edgecolor='none' '', the code may produce a graph with wide black edges, which \n",
    "# will make the surface look much darker than the one illustrated in the figure above.\n",
    "ax.plot_surface(X, Y, Z, rstride = 1, cstride = 1, norm = LogNorm(), cmap = cm.viridis, linewidth=0, edgecolor='none')\n",
    "\n",
    "# Set the axis limits so that they are the same as in the figure above.\n",
    "ax.set_xlim([-2, 2.0])                                                       \n",
    "ax.set_ylim([-1, 3.0])                                                       \n",
    "ax.set_zlim([0, 2500]) \n",
    "\n",
    "plt.xlabel(\"x\")\n",
    "plt.ylabel(\"y\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Find the *minimum* of the test function `rosenbrock` defined above.  Use `scipy.optimize.minimize`, and the following template:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from scipy import optimize\n",
    "\n",
    "def cost_f(p):\n",
    "    x, y = p\n",
    "    return rosenbrock(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Plotting"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Generate some random data using:\n",
    "\n",
    "```\n",
    "np.random.seed(0)\n",
    "\n",
    "mu = 200\n",
    "sigma = 25\n",
    "n_bins = 50\n",
    "x = np.random.normal(mu, sigma, size=100)\n",
    "```\n",
    "\n",
    "Now, try to reproduce this plot:\n",
    "\n",
    "![matplotlib hist example](../images/mpl_hist.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ndimage"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Use `scipy.ndimage.distance_transform_edt` to calculate the distance map of the image generated in the next cell:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from skimage import draw\n",
    "\n",
    "N = 200\n",
    "S = 10\n",
    "\n",
    "np.random.seed(0)\n",
    "image = np.ones((N, N), dtype=bool)\n",
    "\n",
    "coords = np.random.randint(low=0, high=N, size=4 * S).reshape(-1, 4)\n",
    "\n",
    "for line in coords:\n",
    "    image[draw.line(*line)] = 0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Display the distance map; can you interpret what you see?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## interpolation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "An image is sampled `T` times by the code below.  Take the coordinates and values of the samples, and\n",
    "try to reconstruct the original image.  **Hint:** Use `scipy.interpolate.griddata`, and provide it with the coordinates of the full image, generated using `np.indices`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from skimage import data, color, filters\n",
    "image = color.rgb2gray(data.astronaut())\n",
    "image = filters.gaussian(image, sigma=2)\n",
    "\n",
    "M, N = image.shape\n",
    "\n",
    "T = 5000  # nr of randomly drawn samples\n",
    "coords = np.column_stack([\n",
    "    np.random.randint(0, M, size=T),\n",
    "    np.random.randint(0, N, size=T)\n",
    "])\n",
    "\n",
    "\n",
    "# Use `coords` and `samples` to reconstruct the image\n",
    "coords = tuple(coords.T)\n",
    "samples = image[coords]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can visualize the data below, to see how densely the image was sampled:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Visualize sampling\n",
    "\n",
    "sampled_image = np.zeros_like(image)\n",
    "sampled_image[coords] = image[coords]\n",
    "\n",
    "f, (ax0, ax1) = plt.subplots(1, 2, figsize=(20, 10))\n",
    "ax0.imshow(image, cmap='gray')\n",
    "ax1.imshow(sampled_image, cmap='gray');"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
